#ifndef EXP_LIST_HPP
#define EXP_LIST_HPP

#include<type_traits>

#include"exp_literal_types.hpp"
#include"exp_select.hpp"

namespace exp_utilities{
    template<class ...Tys>
    struct exp_list;



    namespace exp_list_details {
        template<class TL> struct to_exp_list {};
        template<template<class ...> class TL, class ...Typs> struct to_exp_list<TL<Typs...>>
        {
            using type = exp_list<Typs...>;
        };

        template<typename ...Tys> struct my_list {};

        template<class TL> struct is_exp_list_based : std::false_type {};
        template<template<class ...> class TL, class ...TS>
        struct is_exp_list_based<TL<TS...>>
        {
            static constexpr bool value = std::is_base_of_v<exp_list<TS...>, TL<TS...>>;
        };

        template<class TL>
        using pop_last = std::conditional_t<(TL::length >= 1), typename to_exp_list_select_t<std::make_index_sequence<TL::length - 1>>::template apply<TL>, exp_list<>>;
        
    }

    template<class First, class ...Tys>
    struct exp_list<First, Tys...> {
        static constexpr std::size_t length = sizeof...(Tys) + 1;
        template<template<class...> class TL> using to = TL<First, Tys...>;
        template<template<class> class F> using for_each = exp_list<F<First>, F<Tys>...>;
        template<class T> using push_back = exp_list<First, Tys..., T>;
        template<class T> using push_front = exp_list<T, First, Tys...>;
        using pop_front = exp_list<Tys...>;
        using front = First;
        using back = exp_select<sizeof...(Tys), exp_list_details::my_list<First, Tys...>>;
        template<std::size_t I> requires (I < length)
        using at = exp_select<I, exp_list<First, Tys...>>;
    };

    template<>
    struct exp_list<> {
        static constexpr std::size_t length = 0;
        template<template<class...> class TL> using to = TL<>;
        template<template<class> class F> using for_each = exp_list<>;
        template<class T> using push_back = exp_list<T>;
        template<class T> using push_front = exp_list<T>;
        using pop_front = literal_types::no_exist_type;
        using pop_back = literal_types::no_exist_type;
        using front = literal_types::no_exist_type;
        using back = literal_types::no_exist_type;
    };

    template<class TL>
    using to_exp_list_t = typename exp_list_details::to_exp_list<TL>::type;

    template<class TL>  concept exp_list_based = exp_list_details::is_exp_list_based<TL>::value;
}


#endif // !EXP_LIST_HPP

